home *** CD-ROM | disk | FTP | other *** search
/ Internet Info 1994 March / Internet Info CD-ROM (Walnut Creek) (March 1994).iso / networking / ip / ka9q / aztecnos.arc / HS.C < prev    next >
Encoding:
C/C++ Source or Header  |  1989-02-19  |  13.5 KB  |  549 lines

  1. /* Interface driver for the DRSI PCPA or the Eagle 8530 boards for the IBM PC
  2.  * connected to a WA4DSY 56kbps modem. Uses polling-loop transfers with
  3.  * interrupts disabled for maximum speed.
  4. */
  5. #include <stdio.h>
  6. #include "global.h"
  7. #include "mbuf.h"
  8. #include "iface.h"
  9. #include "hs.h"
  10. #include "8530.h"
  11. #include "ax25.h"
  12. #include "trace.h"
  13.  
  14. extern struct iface *Ifaces;
  15. extern struct mbuf *Hopper;
  16. int (*getirq())();    /* Getirq is a function returning a pointer to
  17.                  * a function returning int */
  18.  
  19. static void hexint(),hrxint(),htxint(),hdlcparam(),flushrx();
  20. int rx8530();
  21.  
  22. struct hs Hs[NHS];
  23. int hs0vec();
  24. int (*Hshandle[])() = { hs0vec };
  25. static struct hdlc Hdlc[2*NHS];
  26. int16 Nhs;
  27.  
  28. /* Master interrupt handler for the PC-100 card. All interrupts come
  29.  * here first, then are switched out to the appropriate routine.
  30.  */
  31. hsint(dev)
  32. int16 dev;
  33. {
  34.     register char iv;
  35.     int16 hsbase;
  36.     register struct hdlc *hp;
  37.     
  38.     Hs[dev].ints++;
  39.     hsbase = Hs[dev].addr;
  40.  
  41. #ifdef    foo
  42.     outportb(hsbase+4,0x8+0x10);    /* HIT EAGLE INTACK */
  43.     (void)inportb(hsbase+CHANA+CTL,R0);
  44.     outportb(hsbase+4,0x8);        /***/
  45. #endif
  46.  
  47.     /* Read interrupt status from channel A */
  48.     while((iv = read_scc(hsbase+CHANA+CTL,R3)) != 0){
  49.         if(iv & CHARxIP){
  50.             /* Channel A Rcv Interrupt Pending */
  51.             hp = &Hdlc[2*dev];
  52.             hrxint(hp);
  53.         } else if(iv & CHATxIP){
  54.             /* Channel A Transmit Int Pending */
  55.             hp = &Hdlc[2*dev];
  56.             htxint(hp);
  57.         } else if(iv & CHAEXT){
  58.             /* Channel A External Status Int */
  59.             hp = &Hdlc[2*dev];
  60.             hexint(hp);
  61.         } else if(iv & CHBRxIP){
  62.             /* Channel B Rcv Interrupt Pending */
  63.             hp = &Hdlc[(2*dev)+1];
  64.             hrxint(hp);
  65.         } else if(iv & CHBTxIP){
  66.             /* Channel B Transmit Int Pending */
  67.             hp = &Hdlc[(2*dev)+1];
  68.             htxint(hp);
  69.         } else if(iv & CHBEXT){
  70.             /* Channel B External Status Int */
  71.             hp = &Hdlc[(2*dev)+1];
  72.             hexint(hp);
  73.         }
  74.         /* Reset interrupt pending state */
  75.         write_scc(hp->ctl,R0,RES_H_IUS);
  76.         outportb(hsbase+CHANA+CTL,0);    /* Restore pointer to 0 */
  77.         outportb(hsbase+CHANB+CTL,0);    /* Restore pointer to 0 */
  78.     }
  79.     outportb(hsbase+CHANA+CTL,0);    /* Restore pointer to 0 */
  80.     outportb(hsbase+CHANB+CTL,0);    /* Restore pointer to 0 */
  81. }
  82. /* HDLC SIO External/Status interrupts
  83.  * The only one that can happen in this driver is a DCD change
  84.  */
  85. static void
  86. hexint(hp)
  87. register struct hdlc *hp;
  88. {
  89.     struct mbuf *rcvbuf;
  90.     struct phdr *phdr;
  91.     char *cp;
  92.     int cnt,data;
  93.     register int ctl;
  94.  
  95.     ctl = hp->ctl;
  96.     data = hp->data;
  97.     hp->exints++;
  98.  
  99.     /* Allocate a receive buffer */
  100.     if((rcvbuf = alloc_mbuf(hp->bufsiz+sizeof(struct phdr))) == NULLBUF){
  101.         /* Alloc failed; refuse to proceed */
  102.         hp->nomem++;
  103.         write_scc(ctl,R0,RES_EXT_INT);
  104.         return;
  105.     }
  106.     /* Allow space for phdr descriptor on front */
  107.     cp = rcvbuf->data + sizeof(struct phdr);
  108.     cnt = 0;
  109.  
  110.     /* Disable DCDIE bit so we can track changes in DCD */
  111.     write_scc(ctl,R15,0);
  112.  
  113.     write_scc(ctl,R3,ENT_HM|RxENABLE|RxCRC_ENAB|Rx8);
  114.     flushrx(data);
  115.     while((cnt = rx8530(ctl,data,cp,hp->bufsiz)) != -1){
  116.         if(cnt > 4){
  117.             /* Good frame */
  118.             hp->good++;
  119.             /* Toss crc */
  120.             rcvbuf->cnt = sizeof(struct phdr) + cnt - 1;
  121.             phdr = (struct phdr *)rcvbuf->data;
  122.             phdr->iface = hp->iface;
  123.             phdr->type = TYPE_AX25;
  124.             enqueue(&Hopper,rcvbuf);
  125.             /* Replenish buffer */
  126.             rcvbuf = alloc_mbuf(hp->bufsiz + sizeof(struct phdr));
  127.         }
  128.         /* Start new buffer */
  129.         if(rcvbuf == NULLBUF)
  130.             break;    /* alloc failed */
  131.         cp = rcvbuf->data + sizeof(struct phdr);
  132.         cnt = 0;
  133.     }    
  134.     write_scc(ctl,R0,RES_EXT_INT);
  135.     write_scc(ctl,R15,DCDIE);    /* Re-enable DCD */
  136.     write_scc(ctl,R3,ENT_HM|RxENABLE|RxCRC_ENAB|Rx8);
  137.  
  138.     /* Get rid of fragmentary buffer */
  139.     free_p(rcvbuf);
  140. }
  141. static void
  142. flushrx(data)
  143. register int16 data;
  144. {
  145.     register int i = 5;
  146.     while(i-- != 0)
  147.         (void)inportb(data);
  148. }
  149. /* HDLC receiver interrupt handler.
  150.  * Not used in this driver
  151.  */
  152. static void
  153. hrxint(hp)
  154. register struct hdlc *hp;
  155. {
  156. }
  157. /* HDLC transmit interrupt service routine
  158.  * Not used in this driver
  159.  */
  160. static void
  161. htxint(hp)
  162. register struct hdlc *hp;
  163. {
  164. }
  165.  
  166. /* (re)Initialize HDLC controller parameters */
  167. static void
  168. hdlcparam(hp)
  169. register struct hdlc *hp;
  170. {
  171.     char i_state;
  172.     register int16 ctl;
  173.  
  174.     /* Initialize 8530 channel for SDLC operation */
  175.     ctl = hp->ctl;
  176.     i_state = dirps();
  177.  
  178. #ifdef    foo
  179.     switch(ctl & 2){
  180.     case CHANA:
  181.         write_scc(ctl,R9,CHRA);    /* Reset channel A */
  182.         break;
  183.     case CHANB:
  184.         write_scc(ctl,R9,CHRB);    /* Reset channel B */
  185.         break;
  186.     }
  187.     pause(1L);    /* Allow plenty of time for resetting */
  188. #endif
  189.  
  190.     /* Deselect interrupts for now */
  191.     write_scc(ctl,R1,0);
  192.     write_scc(ctl,R15,0);
  193.  
  194.     /* X1 clock, SDLC mode, Sync modes enable, parity disable */
  195.     write_scc(ctl,R4,X1CLK | SDLC | SYNC_ENAB);
  196.  
  197.     /* CRC preset 1, NRZ encoding, no active on poll, flag idle,
  198.      * flag on underrun, no loop mode, 8 bit sync
  199.      */
  200.     write_scc(ctl,R10,CRCPS|NRZ);
  201.  
  202.     /* 8530 gets both tx and rx clock from modem.
  203.      * TRxC = receive clock, RTxC = transmit clock
  204.      */
  205.     write_scc(ctl,R11,RCTRxCP | TCRTxCP);
  206.  
  207.     /* Note: baud rate generator not used */
  208.  
  209.     /* Null out SDLC start address */
  210.     write_scc(ctl,R6,0);
  211.  
  212.     /* SDLC flag */
  213.     write_scc(ctl,R7,FLAG);
  214.  
  215.     /* DTR On, 8 bit TX chars, no break, TX enable, SDLC CRC,
  216.      * RTS off, TxCRC enable
  217.      */
  218.     write_scc(ctl,R5,DTR|Tx8|TxENAB|TxCRC_ENAB);
  219.  
  220.     /* 8 bit RX chars, auto enables off, no hunt mode, RxCRC enable,
  221.      * no address search, no inhibit sync chars, disable RX. Rx is
  222.      * started only by an actual DCD interrupt
  223.      */
  224.     write_scc(ctl,R3,RxENABLE|RxCRC_ENAB|Rx8);
  225.  
  226.     /* Dummy interrupt vector
  227.      * (This probably isn't necessary)
  228.      */
  229.     write_scc(ctl,R2,0);
  230.  
  231.     /* Enable only the external interrupts (modem interrupts) since
  232.      * polling is used for all actual tx/rx operations
  233.      */
  234.     write_scc(ctl,R1,EXT_INT_ENAB);
  235.  
  236.     /* Enable only DCD interrupts */
  237.     write_scc(ctl,R15,DCDIE);
  238.  
  239.     /* No reset, status low, master int enable, enable lower chain,
  240.      * no vector
  241.      */
  242.     write_scc(ctl,R9,MIE|NV);
  243.  
  244.     restore(i_state);
  245. }
  246. /* Attach a high speed iterface to the system
  247.  * argv[0]: hardware type, must be "hs"
  248.  * argv[1]: I/O address, e.g., "0x380"
  249.  * argv[2]: vector, e.g., "2"
  250.  * argv[3]: mode, must be "ax25"
  251.  * argv[4]: interface label, e.g., "drsi0". 
  252.  * argv[5]: receiver packet buffer size in bytes
  253.  * argv[6]: maximum transmission unit, bytes
  254.  * argv[7]: keyup delay, clock ticks
  255.  * argv[8]: persistence value, 0-255
  256.  */
  257. int
  258. hs_attach(argc,argv)
  259. int argc;
  260. char *argv[];
  261. {
  262.     register struct iface *if_hsa,*if_hsb;
  263.     struct hdlc *hp;
  264.     int dev;
  265.  
  266.     if(Nhs >= NHS){
  267.         printf("Too many hs controllers\n");
  268.         return -1;
  269.     }
  270.     if(if_lookup(argv[4]) != NULLIF){
  271.         printf("Interface %s already exists\n",argv[4]);
  272.         return -1;
  273.     }
  274.     dev = Nhs++;
  275.  
  276.     /* Initialize hardware-level control structure */
  277.     Hs[dev].addr = htoi(argv[1]);
  278.     Hs[dev].vec = htoi(argv[2]);
  279.  
  280.     /* Save original interrupt vector */
  281.     Hs[dev].save.vec = getirq(Hs[dev].vec);
  282.     /* Set new interrupt vector */
  283.     if(setirq(Hs[dev].vec,Hshandle[dev]) == -1){
  284.         printf("IRQ %u out of range\n",Hs[dev].vec);
  285.         Nhs--;
  286.         return -1;
  287.     }
  288.     /* Create interface structures and fill in details */
  289.     if_hsa = (struct iface *)calloc(1,sizeof(struct iface));
  290.     if_hsb = (struct iface *)calloc(1,sizeof(struct iface));
  291.  
  292.     if_hsa->name = strdup(argv[4]);
  293.     if_hsb->name = strdup(argv[4]);
  294.     if_hsb->name[strlen(argv[4]) - 1]++;    /* kludge */
  295.     if_hsb->mtu = if_hsa->mtu = atoi(argv[6]);
  296.     if_hsa->dev = 2*dev;
  297.     if_hsb->dev = 2*dev + 1;
  298.     if_hsb->stop = if_hsa->stop = hs_stop;
  299.     if_hsb->output = if_hsa->output = ax_output;
  300.     if_hsb->raw = hs_raw;
  301.  
  302.     if(strcmp(argv[3],"ax25") == 0){
  303.         axarp();
  304.         if(Mycall.call[0] == '\0'){
  305.             printf("set mycall first\n");
  306.             free((char *)if_hsa);
  307.             free((char *)if_hsb);
  308.             return -1;
  309.         }        
  310.         if_hsb->send = if_hsa->send = ax_send;
  311.         if(if_hsb->hwaddr == NULLCHAR)
  312.             if_hsb->hwaddr = malloc(sizeof(Mycall));
  313.         memcpy(if_hsb->hwaddr,(char *)&Mycall,sizeof(Mycall));
  314.     } else {
  315.         printf("Mode %s unknown for interface %s\n",
  316.             argv[3],argv[4]);
  317.         free((char *)if_hsa);
  318.         free((char *)if_hsb);
  319.         return -1;
  320.     }
  321.     if_hsa->next = if_hsb;
  322.     if_hsb->next = Ifaces;
  323.     Ifaces = if_hsa;
  324.  
  325.     write_scc(Hs[dev].addr+CHANA+CTL,R9,FHWRES);
  326.     hp = &Hdlc[2*dev+1];
  327.     hp->ctl = Hs[dev].addr + CHANB + CTL;
  328.     hp->data = Hs[dev].addr + CHANB + DATA;
  329.     hp->bufsiz = atoi(argv[5]);
  330.     if(argc > 7)
  331.         hp->txdelay = atol(argv[7]);
  332.     else
  333.         hp->txdelay = 1L;
  334.     if(argc > 8)
  335.         hp->p = atoi(argv[8]);
  336.     else
  337.         hp->p = 64;
  338.     hp->iface = if_hsb;
  339.     hdlcparam(hp);
  340.  
  341.     hp = &Hdlc[2*dev];
  342.     hp->ctl = Hs[dev].addr + CHANA + CTL;
  343.     hp->data = Hs[dev].addr + CHANA + DATA;
  344.     hp->bufsiz = atoi(argv[5]);
  345.     hp->txdelay = Hdlc[2*dev+1].txdelay;
  346.     hp->p = Hdlc[2*dev+1].p;
  347.     hp->iface = if_hsb;
  348.     hp->iface = if_hsa;
  349.     hdlcparam(hp);
  350.  
  351.     outportb(Hs[dev].addr + 4,0x08);    /*EAGLE INT GATE */
  352.     /* Clear mask (enable interrupt) in 8259 interrupt controller */
  353.     maskon(Hs[dev].vec);
  354.  
  355.     return 0;
  356. }
  357. int
  358. hs_stop(iface)
  359. struct iface *iface;
  360. {
  361.     int16 dev;
  362.  
  363.     dev = iface->dev;
  364.     if(dev & 1)
  365.         return -1;    /* Valid only for the first device */
  366.     dev >>= 1;    /* Convert back into hs number */
  367.     /* Turn off interrupts */
  368.     maskoff(Hs[dev].vec);
  369.  
  370.     /* Restore original interrupt vector */
  371.     setirq(Hs[dev].vec,Hs[dev].save.vec);
  372.  
  373.     /* Force hardware reset */
  374.     write_scc(Hs[dev].addr + CHANA+CTL,R9,FHWRES);
  375.     return 0;
  376. }
  377. /* Send raw packet */
  378. int
  379. hs_raw(iface,bp)
  380. struct iface *iface;
  381. struct mbuf *bp;
  382. {
  383.     register int16 cnt;
  384.     register char *cp;
  385.     char *buffer,i_state;
  386.     struct hdlc *hp;
  387.     int16 ctl,data;
  388.     long i;
  389.  
  390.     dump(iface,IF_TRACE_OUT,TYPE_AX25,bp);
  391.     hp = &Hdlc[iface->dev];
  392.     ctl = hp->ctl;
  393.     data = hp->data;
  394.  
  395.     hp->txpkts++;
  396.  
  397.     /* Copy to new buffer for speed */
  398.     cnt = len_mbuf(bp);
  399.     if((cp = buffer = malloc(cnt)) == NULLCHAR){
  400.         hp->nomem++;
  401.         free_p(bp);
  402.         return -1;
  403.     }
  404.     pullup(&bp,cp,cnt);
  405.  
  406.     /* P-persistence. The slot time is fixed at one tick. */
  407.     while((rand() & 0xff) > uchar(hp->p))
  408.         pause(1L);
  409.  
  410.     /* Prevent distractions. In particular, block off the DCD interrupt
  411.      * so we don't hear our own carrier and hang in the interrupt handler!
  412.      * Note that simply disabling CPU interrupts isn't enough since
  413.      * the call to pause will block and the kernel will re-enable
  414.      * them.
  415.      */
  416.     write_scc(ctl,R9,0);    /* Disable all SCC interrupts */
  417.     i_state = dirps();
  418.  
  419.     /* Keyup delay */
  420. #ifdef    notdef    /* Use PC timer, sending marking line during delay */
  421.  
  422.     write_scc(ctl,R5,TxCRC_ENAB | RTS | Tx8 | DTR);
  423.     pause(hp->txdelay);    /* 55 ms units */
  424. #ifdef    notdef
  425.     while(!(read_scc(ctl,R0) & CTS))
  426.         ;
  427. #endif
  428.     /* Now enable transmitter */
  429.     write_scc(ctl,R5,TxCRC_ENAB | RTS | TxENAB | Tx8 | DTR);
  430. #else    /* Delay by sending dummy frame */
  431.  
  432.     /* Turn on carrier, enable transmitter */
  433.     write_scc(ctl,R5,TxCRC_ENAB | RTS | TxENAB | Tx8 | DTR);
  434.  
  435.     for(i=hp->txdelay;i != 0;i--){
  436.         while(!(inportb(ctl) & Tx_BUF_EMP))
  437.             ;
  438.         outportb(data,0);
  439.     }
  440.     write_scc(ctl,R0,RES_EOM_L);    /* Allow CRC generation */
  441.  
  442.     /* End of frame. Wait for TxEOM to go high, indicating start of
  443.      * CRC transmission. Note that we don't reset the transmit interrupt
  444.      * pending flag as one ordinarily would, since we're not using tx
  445.      * interrupts.
  446.      */
  447.     while(!(inportb(ctl) & TxEOM))
  448.         ;
  449. #endif
  450.     /* Initialize transmitter CRC */
  451.     write_scc(ctl,R0,RES_Tx_CRC);
  452.     for(;;){
  453.         /* Wait for the transmitter to become ready */
  454.         while(!(inportb(ctl) & Tx_BUF_EMP))
  455.             ;
  456.         if(cnt-- == 0)
  457.             break;
  458.         outportb(data,*cp++); /* Send the character */
  459.     }
  460.     write_scc(ctl,R0,RES_EOM_L);    /* Allow CRC generation */
  461.  
  462.     /* End of frame. Wait for TxEOM to go high, indicating start of
  463.      * CRC transmission. Note that we don't reset the transmit interrupt
  464.      * pending flag as one ordinarily would, since we're not using tx
  465.      * interrupts.
  466.      */
  467.     while(!(inportb(ctl) & TxEOM))
  468.         ;
  469.  
  470.     /* To allow the SCC buffering to drain, we begin a dummy frame,
  471.      * then abort it
  472.      */
  473.     for(cnt=5;cnt != 0;cnt--){
  474.         while(!(inportb(ctl) & Tx_BUF_EMP))
  475.             ;
  476.         outportb(data,0);
  477.     }
  478.     write_scc(ctl,R0,SEND_ABORT);
  479.  
  480.     /* Turn off carrier and disable transmitter */
  481.     write_scc(ctl,R5,TxCRC_ENAB | Tx8 | DTR);
  482.     /* Re-Enable SCC interrupts */
  483.     write_scc(ctl,R9,MIE|NV);        
  484.     restore(i_state);
  485.     free(buffer);
  486.     return 0;
  487. }
  488. int
  489. dohs(argc,argv)
  490. int argc;
  491. char *argv[];
  492. {
  493.     register int i;
  494.     register struct hdlc *hp;
  495.  
  496.     for(i=0;i<2*Nhs;i++){
  497.         hp = &Hdlc[i];
  498.         printf("port %d: txpkts %lu ints %lu rxpkts %lu rxbytes %lu nomem %lu toobig %lu crcerr %lu aborts %lu overrun %lu\n",
  499.             i,hp->txpkts,hp->exints,hp->good,hp->rxbytes,
  500.             hp->nomem,hp->toobig,hp->crcerr,hp->aborts,hp->overrun);
  501.     }
  502.     return 0;
  503. }
  504. #ifdef    notdef        /* replaced with assembler in 8530.asm */
  505. /* Read data from the 8530 receiver.
  506.  * Returns when either a good frame is received, or when carrier drops.
  507.  * If a good frame is received, the length is returned; otherwise -1.
  508.  */
  509. int
  510. rx8530(ctl,data,buf,bufsize)
  511. int16 ctl,data;
  512. char *buf;
  513. int16 bufsize;
  514. {
  515.     int cnt = 0;
  516.     register char status;
  517.     char error;
  518.     register char *cp = buf;
  519.  
  520.     for(;;){
  521.         status = inportb(ctl);
  522.         if(!(status & DCD)){
  523.             cnt = -1;
  524.             break;
  525.         } else if(status & BRK_ABRT){
  526.             cp = buf;
  527.             cnt = 0;
  528.         } else if(status & Rx_CH_AV){
  529.             /* Receive character is ready, get it */
  530.             *cp++ = inportb(data);
  531.             if(++cnt > bufsize){
  532.                 /* Buffer overflow, start again */
  533.                 write_scc(ctl,R3,ENT_HM|RxENABLE|RxCRC_ENAB|Rx8);
  534.                 cp = buf;
  535.                 cnt = 0;
  536.             }
  537.         } else if((error = read_scc(ctl,R1)) & END_FR){
  538.             if(!(error & CRC_ERR))
  539.                 break;    /* Good frame! */
  540.             /* Bad frame, start again */
  541.             cp = buf;
  542.             cnt = 0;
  543.         }
  544.     }
  545.     return cnt;
  546. }
  547. #endif
  548.  
  549.